﻿using CoAP.Server.Resources;
using Microsoft.Extensions.DependencyInjection;
using MySqlConnector;
using NbMeterServices.Entity;
using NewLife.Redis.Core;
using NewLife.Serialization;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Yitter.IdGenerator;
using Mapster;
using System.Net.Http.Headers;
using NewLife.Data;
using Microsoft.Data.SqlClient.Server;
using System.Globalization;
using Microsoft.AspNetCore.SignalR.Client;
using System.Configuration;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography;
using System.Diagnostics.Metrics;


namespace NbMeterServices
{
    public class CoapResource : Resource
    {
        private string strName;
        private NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
        private HubConnection signalrConnection;
        private IConfiguration _config;
        public CoapResource(string name, IConfiguration config) : base(name)
        {
            Console.WriteLine($"Title {name}");
            Attributes.Title = $"GET a {name} greeting!";
            strName = name;
            _config = config;
            InitSignalR();
        }


        private async void InitSignalR()
        {
            if (signalrConnection != null)
                return;

            var url = _config["SignalR:Urls"];

            signalrConnection = new HubConnectionBuilder()
                .WithServerTimeout(TimeSpan.FromSeconds(60))
                .WithKeepAliveInterval(TimeSpan.FromSeconds(30))                
                .WithUrl(url, o =>
                {
                    //处理ssl问题
                    o.HttpMessageHandlerFactory = (handler) =>
                    {                        
                        if (handler is HttpClientHandler clientHandler)
                        {
                            clientHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
                            clientHandler.ServerCertificateCustomValidationCallback +=
                                (message, certificate2, arg3, arg4) => { return true; };
                        }

                        return handler;
                    };

                })
                .WithAutomaticReconnect()
                .Build();
            signalrConnection.Closed += async (err) =>
            {
                await Task.Delay(new Random().Next(0, 3) * 1000);
                await signalrConnection.StartAsync();
            };

            signalrConnection.Reconnected += connectionId =>
            {
                return Task.CompletedTask;
            };

            signalrConnection.Reconnecting += err =>
            {
                _logger.Info($" signalr_Reconnecting : {signalrConnection.State} == {err}");

                return Task.CompletedTask;
            };

            await signalrConnection.StartAsync();            
        }

        

        private async Task<bool> SendSignalRMessage(string message)
        {
            if (signalrConnection == null &&  signalrConnection?.State != HubConnectionState.Connected)
                return false;

            await signalrConnection.InvokeAsync("PushEvent", message);
            return true;
        }

        private async Task<bool> SendSignalRMessage2(string message)
        {
            if (signalrConnection == null && signalrConnection?.State != HubConnectionState.Connected)
                return false;

            await signalrConnection.InvokeAsync("PushEvents", message);
            return true;
        }

        private async Task<DownloadCmd> GetCmd(string meterNo,int count)
        {
            try
            {
                var sqlSugar = Common.Service.GetService<ISqlSugarClient>();
                var items = await sqlSugar.Queryable<MrMeterCtrlTask>().Where(x => x.MeterNo == meterNo && x.Status == "0" && x.IsDelete == false).OrderBy(x => x.CreateTime).Take(count).ToListAsync();
                if (items.Count == 0) return null;

                var acts = new List<Act>();
                foreach (var it in items)
                {
                    var act = JsonConvert.DeserializeObject<Act>(it.Command);
                    if (act != null)
                    {
                        act.id = it.Id;
                        acts.Add(act);
                    }

                    it.ExecuteTime = DateTime.Now;
                    it.Status = "1";
                }

                var sqlSugar2 = Common.Service.GetService<ISqlSugarClient>();
                await sqlSugar2.Updateable<MrMeterCtrlTask>(items).ExecuteCommandAsync();

                var cmd = new DownloadCmd
                {
                    No = meterNo,
                    Flag = 1,
                    Time = $"{DateTime.Now:yyyyMMddHHmmss}",
                    Act = acts,
                    //count = acts.Count()
                };


                return cmd;
            }
            catch (Exception ex)
            {
                _logger.Error(ex.ToString());
                return null;
            }
            
        }


        // override this method to handle GET requests
        protected override async void DoGet(CoapExchange exchange)
        {
            //var info333 = new MrEvent
            //{
            //    DataTime = DateTime.Now,
            //    MeterId = 508960706805893,
            //    MeterNo = "011124011111",
            //    EventType = 10004,
            //    Source = "Meter",
            //    Message = $"您的账户当前余额不足,余额为 {2},低于设定的提醒值 {3},为了不影响正常用水，请及时充值!"
            //};

            //SendSignalRMessage(JsonConvert.SerializeObject(info333));

            //return;









            Console.ForegroundColor = ConsoleColor.White;
            if (exchange.Request.Payload == null) return;
            var payload = Encoding.UTF8.GetString(exchange.Request.Payload);
            Console.WriteLine(payload);
            _logger.Info($"原始数据：{payload}");
            MrMeterJk data = null;
            //可用水量
            decimal? waterRemain = 0m;
            
            DateTime dataTime = DateTime.Now;

            var lstEvents = new List<MrEvent>();
            try
            { 
                data = JsonConvert.DeserializeObject<MrMeterJk>(payload);
                data?.Process();

                //dataTime = DateTime.ParseExact(data.Time, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
                data.DataTime = dataTime;

                if (data.Error != null)
                {
                    var msg = "";
                    foreach (var item in Common.LstEventItem)
                    {
                        if ((data.Error.Value & (1 << item.Index)) != 0)
                        {
                            msg += item.Description + ",";
                            var mrMsg = new MrEvent()
                            {
                                DataTime = dataTime,
                                EventType = item.EventType,
                                EventLevel = item.EventLevel,
                                Source = "Meter",
                                Message = item.Description,
                                MeterNo = data.No
                            };

                            lstEvents.Add(mrMsg);
                        }
                    }

                    data.ErrorInfo = msg;
                }
                
                //data.DataTime = DateTime.ParseExact(data.Time, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
                data.DataTime = dataTime;
            }
            catch(Exception ex)
            {
                _logger.Error(payload + "\r\n" + ex.ToString());
                //转换失败:报文错误
                var info1 = new DownloadCmd
                {
                    No = data?.No,
                    Flag = 2,
                    Time = $"{DateTime.Now:yyyyMMddHHmmss}"
                    //Time = $"{data?.DataTime:yyyyMMddHHmmss}"
                };


                _logger.Info($"下发报文错误 {info1.ToJson()}");
                exchange.Respond(info1.ToJson());


                var info = new MrEvent
                {
                    DataTime = DateTime.Now,
                    MeterId = 0,
                    MeterNo = "",
                    EventType = 10028,
                    Source = "Meter",
                    Message = payload
                };

                SendSignalRMessage(JsonConvert.SerializeObject(info));
                return;
            }


            
            MrMeter meter = null;
            MrMeterDataDay meterDay = null;

            //Flag == 2,3是上报和主动上报，4是应答
            if (data.Flag.Value == 4)
            {
                var sqlSugar2 = Common.Service.GetService<ISqlSugarClient>();
                if (data.Act != null)
                {
                    foreach (var item in data.Act)
                    {
                        if (item.id != 0)
                        {
                            //更新命令状态
                            var task = await sqlSugar2.Queryable<MrMeterCtrlTask>().SingleAsync(x => x.Id == item.id);
                            task.ReplyTime = dataTime;
                            if (item.value.ToString() == "1")
                                task.Status = "1";
                            else
                                task.Status = "2";
                            await sqlSugar2.Updateable(task).ExecuteCommandAsync();
                        }
                    }
                }

                var cmd2 = await GetCmd(data.No,3);
                if (cmd2!= null)
                {
                    exchange.Respond(cmd2.ToJson());
                    return;
                }

                cmd2 = new DownloadCmd
                {
                    No = data?.No,
                    Flag = 0,
                    Time = $"{dataTime:yyyyMMddHHmmss}"
                };

                _logger.Info($"下发应答4 {cmd2.ToJson()}");
                exchange.Respond(cmd2.ToJson());
                return;
            }

            //先看看有没有下发的命令
            var cmd = await GetCmd(data.No,2);

            var sqlSugar = Common.Service.GetService<ISqlSugarClient>();
            try
            {
                //如果Flag 0:测试;1:开户;2:定时上报;3:主动上报;4:应答。                            

                //这里先保存数据,做为记录
                //var history = data.Adapt<MrMeterHistory>();                
                //var result = sqlSugar?.Insertable<MrMeterHistory>(history).ExecuteCommand();
                //先检查有没有仪表
                meter = await sqlSugar?.Queryable<MrMeter>().SingleAsync(x => x.MeterNo == data.No);
                //如果没有该水表就先添加水表
                if (meter == null)
                {
                    var id = YitIdHelper.NextId();
                    var meterNew = new MrMeter
                    {
                        CreateTime = dataTime,
                        ICCID = data.ICCID,
                        IsDelete = false,
                        CreateUserName = "system",
                        MeterNo = data.No,
                        State = 0,
                        BindingType = 0,
                        Id = id,
                        ComState = true,
                        Cyc = data.Cyc,
                        MeterType = "0"
                    };                   

                    if (lstEvents?.Count > 0)
                    {
                        foreach (var evt in lstEvents)
                        {
                            evt.MeterId = id;
                        }
                        SendSignalRMessage2(JsonConvert.SerializeObject(lstEvents));
                    }
                        

                    var JKData = data.Adapt<MrMeterJkData>();
                    JKData.Id = id;
                    JKData.ComStatus = 1;

                    var meterHistory = data.Adapt<MrMeterHistory>();
                    meterDay = new MrMeterDataDay
                    {
                        MeterId = id,
                        DataTime = dataTime,
                        DayUsed = 0,
                        Used = data.Used,
                        Inflow = data.Inflow,
                        DayInflow = 0,
                        Back = data.Back,
                        DayBack = 0,
                        MeterDate = data.DataTime.Value,
                        MeterNo = data.No,
                        UsedDayFirst = data.Used,
                    };

                    await sqlSugar?.Ado.BeginTranAsync(System.Data.IsolationLevel.ReadUncommitted);
                    await sqlSugar?.Insertable<MrMeter>(meterNew).ExecuteCommandAsync();
                    await sqlSugar?.Insertable<MrMeterJkData>(JKData).ExecuteCommandAsync();
                    await sqlSugar?.Insertable<MrMeterHistory>(meterHistory).ExecuteCommandAsync();
                    await sqlSugar?.Insertable<MrMeterDataDay>(meterDay).ExecuteCommandAsync();
                    await sqlSugar?.Ado.CommitTranAsync();
                    _logger.Info($"插入新设备: {data.No}");


                    //if(!string.IsNullOrEmpty(JKData.ErrorInfo))
                    //{
                    //    var info = new MrEvent
                    //    {
                    //        DataTime = DateTime.Now,
                    //        MeterId = meter.Id,
                    //        MeterNo = meter.MeterNo,
                    //        EventType = 10013,
                    //        Source = "Meter",
                    //        Message = JKData.ErrorInfo
                    //    };

                    //    SendSignalRMessage(JsonConvert.SerializeObject(info));
                    //}
                }
                else
                {
                    var JKData = data.Adapt<MrMeterJkData>();
                    JKData.Id = meter.Id;
                    JKData.ComStatus = 1;


                    if (lstEvents?.Count > 0)
                    {
                        foreach (var evt in lstEvents)
                        {
                            evt.MeterId = meter.Id;
                        }
                        SendSignalRMessage2(JsonConvert.SerializeObject(lstEvents));
                    }


                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("插入成功");

                    var meterHistory = data.Adapt<MrMeterHistory>();

                    //检查一下，是否关联到开户信息，如果关联了，说明就是要统计钱数，要把IsEnabled=true。
                    var haveAccount = true;
                    var account = await sqlSugar?.Queryable<MrMeterAccount>().SingleAsync(x => x.MeterId == meter.Id && x.IsDelete == false);
                    if (account == null)
                        haveAccount = false;

                    //先定义一个今天的变量
                    meterDay = await sqlSugar?.Queryable<MrMeterDataDay>().Where(x => x.MeterId == meter.Id).OrderBy(x => x.MeterDate.Date, OrderByType.Desc).FirstAsync();
                    //如果meterDayTemp == null,说明是第一次插入数据，要插入第一次天数据
                    if (meterDay == null)
                    {
                        meterDay = new MrMeterDataDay
                        {
                            MeterDate = dataTime.Date,
                            MeterId = meter.Id,
                            MeterNo = meter.MeterNo,
                            Used = data.Used,
                            Inflow = data.Inflow,
                            Back = data.Back,
                            UsedDayFirst = data.Used,
                            DayUsed = data.Used,
                            IsEnabled = haveAccount
                        };

                        meterDay.DayUsed = 0;
                        meterDay.DayInflow = 0;
                        meterDay.DayBack = 0;

                        meterDay.DataTime = dataTime;

                        await sqlSugar.Insertable<MrMeterDataDay>(meterDay).ExecuteCommandAsync();
                        Console.ForegroundColor = ConsoleColor.Blue;
                        Console.WriteLine($"插入第一次天数据成功 {meterDay}");
                        _logger.Info($"插入第一次天数据成功 {meter.MeterNo}");
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.White;
                        //说明有数据，要先检查数据是否比以前大，如果小，就先报错再插入
                        if (data.Used < meterDay.Used || data.Inflow < meterDay.Inflow || data.Back < meterDay.Back || data.Inflow<data.Back)
                        {
                            _logger.Info($"数据异常 {meter.MeterNo}");
                            //说明数据异常，要先报警，
                            var info = new MrEvent
                            {
                                DataTime = DateTime.Now,
                                MeterId = meter.Id,
                                MeterNo = meter.MeterNo,
                                EventType = 10007,
                                Source = "Meter",
                                Message = $"当前数据:进水{data.Inflow},用水{data.Used},回水{data.Back},上次数据:进水{meterDay.Inflow},用水:{meterDay.Used},回水:{meterDay.Back}"
                            };

                            SendSignalRMessage(JsonConvert.SerializeObject(info));
                        }

                        //检查是否是今天的数据，如果不是今天的数据，就插入新的天数据
                        if (meterDay.MeterDate.Date != dataTime.Date)
                        {   
                            var newMeterDay = new MrMeterDataDay
                            {
                                MeterDate = dataTime.Date,
                                MeterId = meter.Id,
                                MeterNo = meter.MeterNo,
                                Used = data.Used,
                                Inflow = data.Inflow,
                                Back = data.Back,
                                UsedDayFirst = meterDay.Used,
                                DayUsed = data.Used,
                                IsEnabled = haveAccount
                            };

                            newMeterDay.DayUsed = data.Used - meterDay.Used;
                            newMeterDay.DayInflow = data.Inflow - meterDay.Inflow;
                            newMeterDay.DayBack = data.Back - meterDay.Back;
                            newMeterDay.DataTime = dataTime;
                            await sqlSugar?.Insertable<MrMeterDataDay>(newMeterDay).ExecuteCommandAsync();
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine($"插入新天数据成功 {newMeterDay}");
                            _logger.Info($"插入新天数据成功 {meter.MeterNo}");
                        }
                        else
                        {
                            //说明是今天的数据，要更新
                            meterDay.DayUsed += data.Used - meterDay.Used;
                            meterDay.DayInflow += data.Inflow - meterDay.Inflow;
                            meterDay.DayBack += data.Back - meterDay.Back;

                            meterDay.Used = data.Used;
                            meterDay.Inflow = data.Inflow;
                            meterDay.Back = data.Back;

                            meterDay.DataTime = dataTime;
                            Console.ForegroundColor = ConsoleColor.Green;
                            await sqlSugar?.Updateable<MrMeterDataDay>(meterDay).ExecuteCommandAsync();
                            
                            Console.WriteLine($"更新天数据成功 {meterDay}");
                            Console.ForegroundColor = ConsoleColor.White;
                            _logger.Info($"更新天数据成功 {meter.MeterNo}");

                        }
                    }              

                    await sqlSugar?.Updateable<MrMeterJkData>(JKData).Where(x=>x.Id == JKData.Id).ExecuteCommandAsync();
                    await sqlSugar?.Updateable<MrMeter>().SetColumns("ComState",true).SetColumns("Cyc",data.Cyc).Where(x => x.Id == meter.Id).ExecuteCommandAsync();
                    var historyId = await sqlSugar?.Insertable<MrMeterHistory>(meterHistory).ExecuteReturnBigIdentityAsync();

                    //如果表已删除就不计算了
                    List<EventsConfig> lstEventConfig = null;
                    List<EventsConfig> lstEventConfigMeter = null;

                    if (!meter.IsDelete)
                    {
                        var payInfo = await sqlSugar.Queryable<MrMeterAccount>()
                                                .LeftJoin<MrChargingSettings>((a, c) => a.BillingMethod == c.Id)
                                                .Where((a, c) => a.IsDelete == false && a.OwnerId == meter.OwnerId)
                                                .Select((a, c) => new
                                                {
                                                    a.Id,
                                                    //a.Limit1,
                                                    //a.Limit2,
                                                    a.Balance,
                                                    c.BillingCycle,
                                                    c.IsFixedMode,
                                                    c.FixedPrice,
                                                    a.StartingValue,
                                                    a.BalanceCalc,
                                                    c.TierePricingData,
                                                    a.PaymentType,
                                                    c.BillDate,
                                                    c.EventConfig,
                                                    MrEventConfig = a.EventConfig
                                                }).FirstAsync();


                        if (payInfo != null)
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine($"查询到计费信息 {payInfo}");
                            _logger.Info($"查询到计费信息 {payInfo}");

                            if(!string.IsNullOrWhiteSpace(payInfo.EventConfig))
                                lstEventConfig = JsonConvert.DeserializeObject<List<EventsConfig>>(payInfo.EventConfig);

                            if (!string.IsNullOrWhiteSpace(payInfo.MrEventConfig))
                                lstEventConfigMeter = JsonConvert.DeserializeObject<List<EventsConfig>>(payInfo.MrEventConfig);

                            decimal? money = 0m;
                            decimal? balance = 0m;

                            //默认自然月
                            var startDay = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);                            
                            var EndDay = startDay.AddMonths(1);

                            //判断不是自然月，就要计算起始日期和结束日期
                            if (payInfo.BillingCycle == 0)
                            {
                                if (DateTime.Now.Day < payInfo.BillDate)
                                {
                                    EndDay = new DateTime(DateTime.Now.Year, DateTime.Now.Month, payInfo.BillDate.Value);
                                    startDay = EndDay.AddMonths(-1);
                                }
                                else
                                {
                                    startDay = new DateTime(DateTime.Now.Year, DateTime.Now.Month, payInfo.BillDate.Value);
                                    EndDay = startDay.AddMonths(1);
                                }
                            }

                            //这里还有一个方案，就是直接
                            //月相等，说明是刚安装一个月，需要看起始数                            

                            //var waterUse = sqlSugar.Queryable<MrMeterDataDay>().Where(x => x.MeterNo == "011124010001" && x.MeterDate >= DateTime.Parse("2024-01-19") && x.MeterDate <= DateTime.Parse("2024-01-22")).Sum(x => x.DayUsed).Value;
                            var waterInfo = await sqlSugar.Queryable<MrMeterDataDay>().Where(x => x.IsEnabled && x.MeterNo == meterDay.MeterNo && x.MeterDate.Date >= startDay && x.MeterDate.Date < EndDay)
                                .Select(x => new
                                {
                                    DayUsed = SqlFunc.AggregateSum(x.DayUsed),
                                    DayInflow = SqlFunc.AggregateSum(x.DayInflow),
                                    DayBack = SqlFunc.AggregateSum(x.DayBack)
                                }).FirstAsync();
                                
                            //var waterUse = (await sqlSugar.Queryable<MrMeterDataDay>().Where(x => x.IsEnabled && x.MeterNo == meterDay.MeterNo && x.MeterDate.Date >= startDay && x.MeterDate.Date < EndDay).SumAsync(x => x.DayUsed)).Value;
                            var waterUse = waterInfo.DayUsed.Value;
                            if (waterUse < 0)
                                waterUse = 0;
                            {
                                await sqlSugar?.Ado.BeginTranAsync(System.Data.IsolationLevel.ReadUncommitted);
                                if (payInfo.IsFixedMode)
                                {
                                    money = waterUse * payInfo.FixedPrice;
                                    //更新数据库，由WEB去做报警
                                    balance = Math.Round((payInfo.Balance.Value - money).Value, 2);
                                    

                                    if (payInfo.PaymentType.Trim() == "0")
                                    {
                                        waterRemain = Math.Round((balance / payInfo.FixedPrice).Value, 3);
                                        await sqlSugar.Updateable<MrMeterJkData>().SetColumns("Balance", waterRemain).Where(x => x.Id == meterDay.MeterId).ExecuteCommandAsync();
                                    }
                                    else
                                        waterRemain = 100;


                                    //在客户账号表里插入本月类似用水 
                                    await sqlSugar.Updateable<MrMeterAccount>().SetColumns("Balance", waterRemain)
                                        .SetColumns("BalanceCalc", money)
                                        .SetColumns("MonthWaterUsed", waterUse)
                                        .Where(x => x.Id == payInfo.Id).ExecuteCommandAsync();


                                    await sqlSugar.Updateable<MrMeterHistory>().SetColumns("Balance", waterRemain)
                                        .SetColumns("MonthWaterUsed", waterUse)
                                        .SetColumns("MoneyUsed", money)
                                        .SetColumns("MoneyBalance", balance)
                                        .Where(x => x.Id == historyId).ExecuteCommandAsync();
                                }
                                else
                                {
                                    if (!string.IsNullOrWhiteSpace(payInfo.TierePricingData))
                                    {
                                        var lstPrice = JsonConvert.DeserializeObject<List<TierePricing>>(payInfo.TierePricingData);
                                        if (lstPrice != null && lstPrice.Count > 0)
                                        {
                                            var prices = lstPrice.OrderBy(x => x.Threshold).ToList();

                                            money = WaterBillCalc.CalculateBill(waterUse, prices);
                                            balance = Math.Round((payInfo.Balance.Value - money).Value, 2);
                                            

                                            if (payInfo.PaymentType.Trim() == "0")
                                            {
                                                waterRemain = Math.Round(WaterBillCalc.CalculateWater(payInfo.Balance.Value, prices) - waterUse, 3);
                                                await sqlSugar.Updateable<MrMeterJkData>().SetColumns("Balance", waterRemain).Where(x => x.Id == meterDay.MeterId).ExecuteCommandAsync();
                                            }
                                            else
                                                waterRemain = 100m;

                                            await sqlSugar.Updateable<MrMeterAccount>()
                                                .SetColumns("BalanceCalc", money)
                                                .SetColumns("MonthWaterUsed", waterUse)
                                                .SetColumns("WaterRemain", waterRemain)
                                                .Where(x => x.Id == payInfo.Id).ExecuteCommandAsync();

                                            await sqlSugar.Updateable<MrMeterHistory>().SetColumns("Balance", waterRemain)
                                                .SetColumns("MonthWaterUsed", waterUse)
                                                .SetColumns("MoneyUsed", money)
                                                .SetColumns("MoneyBalance", balance)
                                                .Where(x => x.Id == historyId).ExecuteCommandAsync();
                                        }
                                    }
                                }

                                await sqlSugar?.Ado.CommitTranAsync();

                                Console.ForegroundColor = ConsoleColor.Yellow;
                                Console.WriteLine($"{meter.MeterNo} 剩余水量 {waterRemain} 消费金额：{money}");

                                _logger.Info($"用水信息：{DateTime.Now:yyyy-MM-dd HH:mm:ss} {meter.MeterNo} 用水{waterUse} 单价：{payInfo.FixedPrice} ,费用：{money} 余额：{balance}，可用水量：{waterRemain}");


                                Task.Run(() =>
                                {
                                    var lstEvent = new List<MrEvent>();
                                    if (waterRemain == -0)
                                        waterRemain = 0;

                                    //先判断小于最小的数
                                    if (waterRemain <= 0)
                                    {
                                        //先推送一条消息,余额不足
                                        var info = new MrEvent
                                        {
                                            DataTime = DateTime.Now,
                                            MeterId = meter.Id,
                                            MeterNo = meter.MeterNo,
                                            EventType = 10001,
                                            Source = "Meter",
                                            Message = $"您的账户可用水量不足，请及时充值!"
                                        };

                                        _logger.Info(info.ToJson());
                                        lstEvent.Add(info);
                                    }
                                    else
                                    {
                                        //先看看仪表本身全局的有没有配置
                                        List<EventsConfig> config = null;
                                        if (lstEventConfigMeter != null && lstEventConfigMeter.Where(x => x.EventType == 10004 || x.EventType == 10005).Count() == 2)
                                            config = lstEventConfigMeter.Where(x => x.EventType == 10004 || x.EventType == 10005)
                                                                   .Where(x => decimal.TryParse(x.LimitValue, out _))
                                                                   .Select(x => new EventsConfig { EventType = x.EventType, LimitValue = x.LimitValue, EventLevel = x.EventLevel, Enabled = x.Enabled })
                                                                   .OrderByDescending(x => decimal.Parse(x.LimitValue))
                                                                   .ToList();

                                        else if (lstEventConfig != null && lstEventConfig.Where(x => x.EventType == 10004 || x.EventType == 10005).Count() == 2)
                                        //config = lstEventConfig.Where(x => x.EventType == 10004 || x.EventType == 10005).ToList();
                                        {
                                            config = lstEventConfig.Where(x => x.EventType == 10004 || x.EventType == 10005)
                                                                   .Where(x => decimal.TryParse(x.LimitValue, out _))
                                                                   .Select(x => new EventsConfig { EventType = x.EventType, LimitValue = x.LimitValue, EventLevel = x.EventLevel, Enabled = x.Enabled })
                                                                   .OrderByDescending(x => decimal.Parse(x.LimitValue))
                                                                   .ToList();
                                        }
                                        
                                        if (config != null)
                                        {
                                            if (waterRemain <= decimal.Parse(config[1].LimitValue))
                                            {
                                                //先推送一条消息,余额不足
                                                var info = new MrEvent
                                                {
                                                    DataTime = DateTime.Now,
                                                    MeterId = meter.Id,
                                                    MeterNo = meter.MeterNo,
                                                    EventType = 10005,
                                                    Source = "Meter",
                                                    //Message = $"余额:{balance},可用水量:{waterRemain},低于设定的提醒值 {config[1].LimitValue}"
                                                    Message = $"余额:{balance},可用水量:{waterRemain},低于设定的提醒值"
                                                };
                                                _logger.Info(info.ToJson());
                                                lstEvent.Add(info);
                                            }
                                            else if (balance <= decimal.Parse(config[0].LimitValue))
                                            {
                                                //也推送一条 
                                                var info = new MrEvent
                                                {
                                                    DataTime = DateTime.Now,
                                                    MeterId = meter.Id,
                                                    MeterNo = meter.MeterNo,
                                                    EventType = 10004,
                                                    Source = "Meter",
                                                    //Message = $"余额:{balance},低于设定的提醒值 {config[0].LimitValue}"
                                                    Message = $"余额:{balance},可用水量:{waterRemain},低于设定的提醒值"
                                                };
                                                _logger.Info(info.ToJson());
                                                lstEvent.Add(info);
                                            }
                                        }
                                    }

                                    //日用水超限
                                    var event1 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10008, meterDay.DayUsed.Value,out string limitValue1);
                                    if (event1!= null)
                                    {
                                        event1.Message = $"日用水当前：{meterDay.DayUsed.Value},超过阈值:{limitValue1}";
                                    }
                                    lstEvent.AddIfNotNull(event1);

                                    var event2 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10009, meterDay.DayInflow.Value, out string limitValue2);
                                    if (event2 != null)
                                    {
                                        event2.Message = $"日进水当前：{meterDay.DayInflow.Value},超过阈值:{limitValue2}";
                                    }
                                    lstEvent.AddIfNotNull(event2);

                                    var event3 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10010, meterDay.DayBack.Value, out string limitValue3);
                                    if (event3 != null)
                                    {
                                        event3.Message = $"日回水当前:{meterDay.DayInflow.Value},超过阈值:{limitValue3}";
                                    }
                                    lstEvent.AddIfNotNull(event3);

                                    var event4 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10015, waterInfo.DayUsed.Value, out string limitValue4);
                                    if (event1 != null)
                                    {
                                        event4.Message = $"月用水当前:{waterInfo.DayUsed.Value},超过阈值:{limitValue4}";
                                    }
                                    lstEvent.AddIfNotNull(event4);

                                    var event5 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10016, waterInfo.DayInflow.Value, out string limitValue5);
                                    if (event5 != null)
                                    {
                                        event5.Message = $"月进水当前:{waterInfo.DayInflow.Value},超过阈值:{limitValue5}";
                                    }
                                    lstEvent.AddIfNotNull(event5);

                                    var event6 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10017, waterInfo.DayBack.Value, out string limitValue6);
                                    if (event6 != null)
                                    {
                                        event6.Message = $"月回水当前:{waterInfo.DayBack.Value},超过阈值:{limitValue6}";
                                    }
                                    lstEvent.AddIfNotNull(event6);

                                    var event7 = GetEvent(lstEventConfig, lstEventConfigMeter, meterDay, 10018, money.Value, out string limitValue7);
                                    if (event7 != null)
                                    {
                                        event7.Message = $"月用水金额当前:{money.Value},超额提醒:{limitValue7}";
                                    }
                                    lstEvent.AddIfNotNull(event7);

                                    if (lstEvent.Count > 0) SendSignalRMessage2(JsonConvert.SerializeObject(lstEvent));
                                });
                                

                                var act = new Act()
                                {
                                    id = 0,
                                    cmd = 6,
                                    addr = "Balance",
                                    value = (double)waterRemain
                                };

                                if (cmd == null)
                                {
                                    cmd = new DownloadCmd
                                    {
                                        //count = 1,
                                        No = data?.No,
                                        Flag = 1,
                                        Time = $"{DateTime.Now:yyyyMMddHHmmss}"
                                    };
                                    cmd.Act = new List<Act>();
                                    cmd.Act.Add(act);
                                }
                                else
                                {
                                    cmd.Act.Add(act);
                                    //cmd.count++;
                                }
                            }

                        }
                    }
                    
                   
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex.ToString());
                //服务器异常
                var info2 = new DownloadCmd
                {
                    No = data?.No,
                    Flag = 6,
                    Time = $"{dataTime:yyyyMMddHHmmss}"
                };

                _logger.Info($"下发系统错误 {info2.ToJson()}");
                exchange.Respond(info2.ToJson());



                var info = new MrEvent
                {
                    DataTime = DateTime.Now,
                    MeterId = 0,
                    MeterNo = "",
                    EventType = 10012,
                    Source = "Meter",
                    Message = payload
                };

                SendSignalRMessage(JsonConvert.SerializeObject(info));
                return;



                return;
            }

            //检查有没有要做的事,没有就开始回复数据，让其下线
            //此处要下载可用水的数量

            if (cmd == null)
            {
                var info3 = new DownloadCmd
                {
                    No = data?.No,
                    Flag = 0,
                    Time = $"{dataTime:yyyyMMddHHmmss}"
                };
                _logger.Info($"下发无操作 {cmd.ToJson()}");
                exchange.Respond(info3.ToJson());
                return;
            }
            else
            {
                _logger.Info($"下发其它 {cmd.ToJson()}");
                exchange.Respond(cmd.ToJson());                
                return;
            }
        }

        protected override void DoPost(CoapExchange exchange)
        {
            // now we get a request, respond it                       
        }



        private MrEvent GetEvent(List<EventsConfig> globalConfig, List<EventsConfig> meterConfig, MrMeterDataDay meterDay, int eventType, decimal value,out string limitValue)
        {
            limitValue = "";
            var config = globalConfig?.SingleOrDefault(x => x.EventType == eventType);
            var configMeter = meterConfig?.SingleOrDefault(x => x.EventType == eventType);
            //走仪表的配置
            if (configMeter != null)
            {
                if (configMeter.Enabled && !string.IsNullOrWhiteSpace(configMeter.LimitValue))
                {
                    if (value >= decimal.Parse(configMeter.LimitValue))
                    {
                        limitValue = configMeter.LimitValue;
                        var info = new MrEvent
                        {
                            DataTime = DateTime.Now,
                            MeterId = meterDay.MeterId,
                            MeterNo = meterDay.MeterNo,
                            EventLevel = configMeter.EventLevel,
                            EventType = configMeter.EventType,
                            Source = "Meter",
                            LimitValue = configMeter.LimitValue                            
                        };
                        return info;
                    }
                }

            }
            else if (config != null)
            {
                //走全局配置
                if (config.Enabled && !string.IsNullOrWhiteSpace(config.LimitValue))
                {
                    if (value >= decimal.Parse(config.LimitValue))
                    {
                        limitValue = config.LimitValue;
                        var info = new MrEvent
                        {
                            DataTime = DateTime.Now,
                            MeterId = meterDay.MeterId,
                            MeterNo = meterDay.MeterNo,
                            EventLevel = config.EventLevel,
                            EventType = config.EventType,
                            Source = "Meter",
                            LimitValue = config.LimitValue                            
                        };
                        return info;
                    }
                }
            }

            return null;
        }
    }   
}
